package com.freeman.cement.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.freeman.cement.entity.hikvision.HikResultObject;
import com.freeman.cement.exception.AppException;
import com.freeman.cement.exception.AppExceptionCodeMsg;
import com.freeman.cement.mapper.BjdbDao;
import com.freeman.cement.mapper.CjdbDao;
import com.freeman.cement.mapper.StaffDao;
import com.freeman.cement.entity.*;
import com.freeman.cement.myenum.ProcessingFlow;
import com.freeman.cement.service.EventDataService;
import com.freeman.cement.util.DateUtils;
import com.freeman.cement.util.SysConst;
import com.freeman.cement.util.hikiscUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import com.freeman.cement.mapper.DeptDao;
import com.freeman.cement.entity.Dept;

import javax.annotation.Resource;
import javax.net.ssl.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.freeman.cement.util.file.FileUtils.readInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Service
public class EventDataServiceImpl implements EventDataService {

    private static final Logger logger = LoggerFactory.getLogger(EventDataServiceImpl.class);

    @Resource
    private BjdbDao bjdbDao;

    @Resource
    private CjdbDao cjdbDao;

    @Resource
    private StaffDao staffDao;

    @Resource
    private DeptDao deptDao;

    private Date dateStringToDate(String time) {
        Date date = null;
        if (StringUtils.isNotBlank(time)) {
            try {
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                date = simpleDateFormat.parse(time);
            } catch (Exception e) {
                throw new AppException(AppExceptionCodeMsg.TIME_STRING_FORMAT_IS_WRONG);
            }
        }
        return date;
    }

    @Override
    public ResponseResult selectEvents(MyEvent myEvent, String begin, String end, int pageNo, int pageSize) {
        Date _begin = null;
        Date _end = null;

        //验证分页范围
        if (pageNo < 1 || pageSize > 1000) {
            throw new AppException(AppExceptionCodeMsg.PAGE_NO_OR_SIZE_WRONG);
        }
        
        // 获取当前用户角色和用户ID
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String userRole = (String) request.getAttribute("userRole");
        
        // 如果不是管理员，且没有指定值班室ID，则使用用户所在的值班室ID
        if (!"管理员".equals(userRole) && (myEvent == null || myEvent.getDutyRoomId() == null)) {
            Integer userId = (Integer) request.getAttribute("userId");
            Dept userDept = deptDao.selectDutyRoomByid(userId);
            if (userDept != null) {
                if (myEvent == null) {
                    myEvent = new MyEvent();
                }
                myEvent.setDutyRoomId(userDept.getId());
            } else {
                // 如果用户没有关联值班室，返回空列表
                return ResponseResult.success(new PageInfo<>(new ArrayList<>()));
            }
        }

        //验证开始时间
        if (StringUtils.isNotBlank(begin)) {
            _begin = dateStringToDate(begin);
        }
        //验证结束时间
        if (StringUtils.isNotBlank(end)) {
            _end = dateStringToDate(end);
        }

        PageHelper.startPage(pageNo, pageSize, true);
        List<MyEvent> list = bjdbDao.selectEvents(myEvent, _begin, _end);
        
        // 处理事件类型名称
        if (list != null) {
            list.stream()
                    .filter(s -> StringUtils.isNotBlank(s.getEventType()) && StringUtils.isBlank(s.getEventName()))
                    .forEach(s -> s.setEventName("未知类型"));
                    
            // 添加事件等级处理逻辑
            list.forEach(event -> {
                if (event.getEventLvl() != null) {
                    switch (event.getEventLvl()) {
                        case 1:
                            event.setEventLvlName("低等级");
                            break;
                        case 2:
                            event.setEventLvlName("中等级");
                            break;
                        case 3:
                            event.setEventLvlName("高等级");
                            break;
                        default:
                            event.setEventLvlName("未知等级");
                    }
                }
            });
        }
        
        PageInfo<MyEvent> pageInfo = new PageInfo<MyEvent>(list);
        return ResponseResult.success(pageInfo);
    }

    @Override
    public ResponseResult selectUnhandleEventCount(int dutyRoomId) {
        if (dutyRoomId > 0) {
            MyEvent myEvent = new MyEvent();
            myEvent.setDutyRoomId(dutyRoomId);
            myEvent.setStatus(ProcessingFlow.UNTREATED.getIndex());
            List<MyEvent> list = bjdbDao.selectEvents(myEvent, null, null);
            int count = (list == null ? 0 : list.size());
            return ResponseResult.success(count);
        } else {
            throw new AppException(AppExceptionCodeMsg.ID_IS_NULL);
        }
    }

    @Override
    public ResponseResult findEventDetail(String eventId) {
        MyEvent _event = bjdbDao.findEventDetail(eventId);
        if (_event != null && StringUtils.isNotBlank(_event.getEventType()) && StringUtils.isBlank(_event.getEventName())) {
            _event.setEventName("未知类型");
        }
        if (_event != null) {
            return ResponseResult.success(_event);
        } else {
            throw new AppException(AppExceptionCodeMsg.ID_NOT_EXISTS);
        }
    }

    @Override
    public ResponseResult getEventDetail(int id) {
        if (id > 0) {
            MyEvent _event = bjdbDao.getEventDetail(id);
            if (_event != null && StringUtils.isNotBlank(_event.getEventType()) && StringUtils.isBlank(_event.getEventName())) {
                _event.setEventName("未知类型");
            }
            if (_event != null) {
                return ResponseResult.success(_event);
            } else {
                throw new AppException(AppExceptionCodeMsg.ID_NOT_EXISTS);
            }

        } else {
            throw new AppException(AppExceptionCodeMsg.ID_IS_NULL);
        }
    }

    /**
     * 图片服务器本地存放地址：
     * e:/WebApp/CementMonitorManagement/EventPic/2023/02/10/20230210084740A002.jpg
     * 图片局域网下访问地址：
     * http://10.35.0.76:8182/sysmanage/static/EventPic/2023/02/09/20230209235458A001.jpg
     * 外网访问地址（通过nginx进行转发）：
     * http://106.117.221.59:8181/dataservice/sysmanage/static/EventPic/2023/02/09/20230209235458A001.jpg
     * http://106.117.221.59:8181/dataservice/sysmanage/static/EventPic/2023/02/10/20230210084740A002.jpg
     * @param uri
     * @return
     */
    @Override
    public Map<String, String> getEventPicMap(String uri) throws Exception {
        if (StringUtils.isNotBlank(uri)) {
            try {
                logger.info("开始下载图片: {}", uri);
                HttpURLConnection httpURLConnection;
                
                //定义一个URL对象，就是你想下载的图片的URL地址
                URL url = new URL(uri);
                
                // 根据协议类型创建不同的连接
                if ("https".equalsIgnoreCase(url.getProtocol())) {
                    logger.info("使用HTTPS连接下载图片");
                    // trust all hosts
                    trustAllHosts();
                    HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection();
                    httpsURLConnection.setHostnameVerifier(DO_NOT_VERIFY);
                    httpURLConnection = httpsURLConnection;
                } else {
                    logger.info("使用HTTP连接下载图片");
                    httpURLConnection = (HttpURLConnection) url.openConnection();
                }
                
                //设置请求方式为"GET"
                httpURLConnection.setRequestMethod("GET");
                //超时响应时间为10秒
                httpURLConnection.setConnectTimeout(10 * 1000);
                logger.info("开始建立连接...");

                int responseCode = httpURLConnection.getResponseCode();
                logger.info("服务器响应码: {}", responseCode);
                
                if (responseCode == HttpURLConnection.HTTP_OK) {
                    logger.info("连接成功，开始读取图片数据");
                    //通过输入流获取图片数据
                    InputStream inputStream = httpURLConnection.getInputStream();
                    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                    int len = 0;
                    byte[] bytes = new byte[1024];
                    int totalBytes = 0;
                    while ((len = inputStream.read(bytes)) != -1) {
                        byteArrayOutputStream.write(bytes, 0, len);
                        totalBytes += len;
                    }
                    inputStream.close();
                    logger.info("图片数据读取完成，总大小: {} 字节", totalBytes);

                    String picPath = DateUtils.datePath() + "/"
                            + System.currentTimeMillis() + "_" + UUID.randomUUID().toString().replace("-", "").substring(0, 8)
                            + ".jpg";
                    String imgPath = SysConst.EventPicBasePath + "/" + picPath;
                    String imgUrl = SysConst.EventUriPicPrefix + "/" + picPath;

                    //创建一个文件对象用来保存图片
                    File imageFile = new File(imgPath);
                    if (!imageFile.exists()) {
                        if (!imageFile.getParentFile().exists()) {
                            imageFile.getParentFile().mkdirs();
                        }
                    }
                    logger.info("开始保存图片到本地: {}", imgPath);
                    //创建输出流
                    FileOutputStream outStream = new FileOutputStream(imageFile);
                    //写入数据
                    outStream.write(byteArrayOutputStream.toByteArray());
                    byteArrayOutputStream.close();
                    //关闭输出流，释放资源
                    outStream.close();
                    logger.info("图片保存成功");

                    Map<String, String> map = new HashMap<>();
                    map.put("path", imgPath);
                    map.put("url", imgUrl);
                    return map;
                } else {
                    logger.error("服务器返回错误响应码: {}", responseCode);
                    return null;
                }
            } catch (Exception e) {
                logger.error("下载图片失败: {}, URL: {}", e.getMessage(), uri, e);
                throw e;
            }
        } else {
            logger.warn("图片URL为空");
            return null;
        }
    }

    @Override
    public ResponseResult getEventPic(String uri) {
        if (StringUtils.isNotBlank(uri)) {
            try {
                Map<String, String> map = getEventPicMap(uri);
                if (map != null) {
                    return ResponseResult.success(map);
                } else {
                    return ResponseResult.error(500, "无法获取报警图片");
                }
            } catch (Exception e) {
                e.printStackTrace();
                throw new AppException(500, e.toString());
            }
        } else {
            throw new AppException(AppExceptionCodeMsg.CONTENT_IS_NULL);
        }
    }

    @Override
    public String getEventPicFromHikiscById(int id) {
        if(id > 0){
            MyEvent event = bjdbDao.getEventDetail(id);
            if(event != null){
                if(StringUtils.isNotBlank(event.getImageUrl())){
                    return hikiscUtil.getPicUrlByJsonStr(event.getImageUrl());
                } else {
                    throw new AppException(55090, "数据库中无报警图片记录");
                }
            } else {
                throw new AppException(AppExceptionCodeMsg.ID_NOT_EXISTS);
            }
        } else {
            throw new AppException(AppExceptionCodeMsg.ID_IS_NULL);
        }
    }

    /***
     * 通过事件id获取报警图片地址，会将报警图片从海康平台下载到服务器本地
     * @param id
     * @return
     */
    @Override
    public ResponseResult getEventPicById(int id) {
        if(id > 0){
            MyEvent event = bjdbDao.getEventDetail(id);
            if(event != null){
                if(StringUtils.isNotBlank(event.getImageUrl())){
                    String result = hikiscUtil.getPicUrlByJsonStr(event.getImageUrl());
                    if(StringUtils.isNotBlank(result)){
                        try {
                            HikResultObject ro = JSONObject.parseObject(result, HikResultObject.class);
                            if (ro.getCode().equals("0"))
                            {
                                JSONObject data = JSONObject.parseObject(ro.getData());
                                String picUrl = data.getString("picUrl");
                                if(StringUtils.isNotBlank(picUrl)){
                                    try {
                                        Map<String, String> map = getEventPicMap(picUrl);
                                        if (map != null) {
                                            if(map.containsKey("url") && StringUtils.isNotBlank(map.get("url"))){
                                                //url地址存入数据库，每次下载后都会更新
                                                bjdbDao.updatePicUrl(id, map.get("url"));
                                            }
                                            return ResponseResult.success(map);
                                        } else {
                                            return ResponseResult.error(500, "无法获取报警图片");
                                        }
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                        throw new AppException(500, e.toString());
                                    }
                                } else {
                                    throw new AppException(55093, "平台返回报警图片地址为空");
                                }
                            } else {
                                throw new AppException(55092, "解析报警图片地址错误，错误码" + ro.getCode());
                            }
                        }catch(Exception e)
                        {
                            e.printStackTrace();
                            throw new AppException(55092, "解析报警图片地址错误");
                        }
                    } else {
                        throw new AppException(55091, "平台未返回报警图片地址");
                    }
                } else {
                    throw new AppException(55090, "数据库中无报警图片记录");
                }
            } else {
                throw new AppException(AppExceptionCodeMsg.ID_NOT_EXISTS);
            }
        } else {
            throw new AppException(AppExceptionCodeMsg.ID_IS_NULL);
        }
    }

    final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };

    /**
     * 不检查任何证书
     */
    private static void trustAllHosts() {
        final String TAG = "trustAllHosts";
        // 创建信任管理器
        TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {

            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[]{};
            }

            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                //不检查
                //Log.i(TAG, "checkClientTrusted");
            }

            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                //不检查
                //Log.i(TAG, "checkServerTrusted");
            }
        }};

        // Install the all-trusting trust manager
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private MyEvent checkEventId(String eventId) {
        if (eventId != null && StringUtils.isNotBlank(eventId)) {
            MyEvent event = bjdbDao.getEventDetailByEventId(eventId);
            if (event != null) {
                return event;
            } else {
                throw new AppException(AppExceptionCodeMsg.ID_NOT_EXISTS);
            }
        } else {
            throw new AppException(AppExceptionCodeMsg.ID_IS_NULL);
        }
    }

    @Override
    public ResponseResult findEventProcessBar(String eventId) {
        MyEvent _event = checkEventId(eventId);
        int lastproc = 0;
        List<HandleRecord> list = new ArrayList<>();
        if (_event != null) {
            lastproc = _event.getStatus();
        }
        for (ProcessingFlow flow : ProcessingFlow.values()) {
            /**
             * 查找出当前状态之前的状态集合，这样的话可以实现发生再次下发处理后各状态显示上的逻辑连贯
             */
            if (flow.getIndex() < ProcessingFlow.ERROR.getIndex() && flow.getIndex() <= lastproc) {
                HandleRecord record = cjdbDao.findHandleRecord(eventId, flow.getIndex());
                if (record != null) {
                    list.add(record);
                }
            }
        }
        return ResponseResult.success(list);
    }

    @Override
    public ResponseResult findEventProcessRecords(String eventId) {
        checkEventId(eventId);
        List<HandleRecord> list = cjdbDao.findEventProcessRecords(eventId);
        return ResponseResult.success(list);
    }

    @Override
    public ResponseResult findEventHandlers(String eventId) {
        MyEvent myEvent = checkEventId(eventId);
        List<Map<String, Object>> list = new ArrayList<>();
        String handlers = myEvent.getEventHandlers();
        if (StringUtils.isNotBlank(handlers)) {
            //final String seperator = ";,;";
            final String seperator = ";";
            final String[] hands = StringUtils.split(handlers, seperator);
            if (hands.length > 0) {
                list = new ArrayList<>();
                for (final String str : hands) {
                    Staff next = staffDao.getStaffById(NumberUtils.toInt(str));
                    if (next != null) {
                        Map<String, Object> map = new HashMap<>();
                        map.put("userId", next.getId());
                        map.put("realname", next.getRealname());
                        map.put("deptId", next.getDeptId());
                        map.put("deptName", next.getDeptName());
                        map.put("worksectionId", next.getWorksectionId());
                        map.put("worksection", next.getWorksection());
                        map.put("userPhone", next.getUserPhone());
                        list.add(map);
                    }
                }
            }
        }
        return ResponseResult.success(list);
    }

}
